package com.gking.resourcePool.config;


import com.gking.resourcePool.realm.*;
import com.gking.resourcePool.service.RemoteInteraction.RemoteInteractionService;
import lombok.extern.slf4j.Slf4j;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy;
import org.apache.shiro.authc.pam.ModularRealmAuthenticator;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.StringRedisTemplate;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;


@Slf4j
@Configuration
public class ShiroConfig {

    @Autowired
    private MyRealm myRealm;

    @Autowired
    private MyRealmTwo myRealmTwo;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RemoteInteractionService remoteInteractionService;

    //配置 SecurityManager
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
        //1 创建 defaultWebSecurityManager 对象
        // DefaultWebSecurityManager  是 Shiro 安全管理器的默认实现，用于协调 Shiro 的各种安全操作
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();

        //2 创建加密对象，并设置相关属性
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //2.1采用 md5 加密
        matcher.setHashAlgorithmName("md5");
        //2.2 迭代加密次数
        matcher.setHashIterations(3);

        //3 将加密对象存储到 myRealm 中
        myRealm.setCredentialsMatcher(matcher);
        myRealmTwo.setCredentialsMatcher(matcher);

        // 协调和管理多个 Realm 对象
        // AtLeastOneSuccessfulStrategy 是一个认证策略，表示只要至少有一个 Realm 验证成功，就认为整体认证成功。
        ModularRealmAuthenticator authenticator = new ModularRealmAuthenticator();
        authenticator.setAuthenticationStrategy(new AtLeastOneSuccessfulStrategy());
        // 添加自定义的 AuthenticationListener
        authenticator.getAuthenticationListeners().add(new MyAuthenticationListener());
        defaultWebSecurityManager.setAuthenticator(authenticator);


        //4 将 myRealm 存入 defaultWebSecurityManager 对象
        defaultWebSecurityManager.setRealms(Arrays.asList(myRealm, myRealmTwo));
        //4.5 设置 rememberMe
        defaultWebSecurityManager.setRememberMeManager(rememberMeManager());
        //4.6 设置缓存管理器
//        defaultWebSecurityManager.setCacheManager(getEhCacheManager());


        // 返回
        return defaultWebSecurityManager;
    }

    //缓存管理器
    public EhCacheManager getEhCacheManager() {
        EhCacheManager ehCacheManager = new EhCacheManager();
        InputStream is = null;
        try {
            is = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache-shiro.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        CacheManager cacheManager = new CacheManager(is);
        ehCacheManager.setCacheManager(cacheManager);
        return ehCacheManager;
    }

    //cookie 属性设置
    public SimpleCookie rememberMeCookie() {
        SimpleCookie cookie = new SimpleCookie("GKingResourceBedCookie");
        //设置跨域
        //cookie.setDomain(domain);
        // 设置 Cookie 路径（可选）
        cookie.setPath("/");
        // 设置是否禁止客户端脚本访问此 Cookie（可选）
        cookie.setHttpOnly(true);
        // 设置 Cookie 的最大生存时间，
        cookie.setMaxAge(3 * 24 * 60 * 60);
        return cookie;
    }

    //创建 Shiro 的 cookie 管理对象
    public CookieRememberMeManager rememberMeManager() {
        CookieRememberMeManager cookieRememberMeManager = new
                CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());

        cookieRememberMeManager.setCipherKey("1234567890987654".getBytes());
        return cookieRememberMeManager;
    }


    /**
     * 如果userPrefix和proxyTargetClass都为false会导致 aop和shiro权限注解不兼容 资源报错404
     * 因此两个属性至少需要其中一个属性为true才可以
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
//        defaultAdvisorAutoProxyCreator.setUsePrefix(false);
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }


    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(DefaultWebSecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        Map<String, Filter> filters = new HashMap<>();
        filters.put("customAuth", new CustomAuthFilter(stringRedisTemplate, remoteInteractionService));
        shiroFilterFactoryBean.setFilters(filters);

        shiroFilterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition().getFilterChainMap());
        return shiroFilterFactoryBean;
    }


    //配置 Shiro 内置过滤器拦截范围
    @Bean
    public DefaultShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new
                DefaultShiroFilterChainDefinition();

        //设置不认证可以访问的资源
        definition.addPathDefinition("/api/**", "anon");
        definition.addPathDefinition("/remote/api/**", "anon");
        definition.addPathDefinition("/public/**", "anon");

        //设置退出过滤器
//        definition.addPathDefinition("/user/logout", "logout");
        //添加存在用户的过滤器 （remember）
//        definition.addPathDefinition("/user/**", "user");
        //设置需要进行登录认证的拦截范围
//        definition.addPathDefinition("/permissions/**", "authc");

        definition.addPathDefinition("/**", "customAuth"); // 使用自定义过滤器
        return definition;
    }


}
